package agent

import (
	"fmt"
	corev1 "gluenet/internal/agent/api/core/v1"
	"gluenet/internal/agent/depend"
	"gluenet/internal/agent/driver/hostdriver"
	"gluenet/internal/agent/driver/k8sdriver"
	"gluenet/internal/agent/driver/rpcdriver"
	"gluenet/internal/glue-srvp/domain/po"
	vo2 "gluenet/internal/glue-srvp/domain/vo"

	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

const (
	keyAgentConfigPath = "agent.config.path"

	keyConfigAgent = "agent"
)

func init() {
	registerFlags(initConfigFlags)
}

func initConfigFlags(flags *pflag.FlagSet) {
	flags.String(
		keyAgentConfigPath,
		"",
		"Path on which to configure agent",
	)
}

type configBuilder struct {
	cfg *corev1.Agent
}

func NewConfigBuilder() *configBuilder {
	return &configBuilder{&corev1.Agent{}}
}

// 构建agent的配置
func (b *configBuilder) Build(vp *viper.Viper) (*corev1.Agent, error) {
	if err := b.buildFromLocal(vp); err != nil {
		return nil, err
	}

	if err := b.buildFromRegister(depend.Produce[rpcdriver.RpcDriver]()); err != nil {
		return nil, err
	}

	depend.Provide(func() *corev1.Agent {
		return b.cfg
	})

	depend.Provide(func() *corev1.PlatformInfo {
		return &b.cfg.PlatformInfo
	})

	logger.Info(*b.cfg)
	return b.cfg, nil
}

func (b *configBuilder) buildFromLocal(vp *viper.Viper) error {

	vp.SetConfigFile(vp.GetString(keyAgentConfigPath))
	if err := vp.ReadInConfig(); err != nil {
		return err
	}

	if err := vp.UnmarshalKey(keyConfigAgent, b.cfg); err != nil {
		return err
	}

	depend.Provide(func() *viper.Viper {
		return vp
	})

	return nil
}

func (b *configBuilder) buildFromRegister(rd rpcdriver.Manager) (err error) {
	cfg := b.cfg
	// for test
	if cfg.Guid != `` {
		return
	}

	req, err := genAgentRegisterInfo(cfg)
	if err != nil {
		return
	}

	newConfig := new(corev1.Agent)

	resp := &vo2.AgentRegisterRes{Config: newConfig}
	if err = rd.Register(req, resp); err != nil {
		return fmt.Errorf("pull remote config falied: %s", err)
	}

	cfg.Guid = resp.Guid
	// cfg.HttpAddress = newConfig.HttpAddress
	// cfg.HeartBeatInterval = newConfig.HeartBeatInterval
	// cfg.HttpServices = newConfig.HttpServices
	// cfg.RpcServices = newConfig.RpcServices
	// cfg.MonitorComponents = newConfig.MonitorComponents

	return nil
}

const (
	platformK8s     = "kubernetes"
	platformGluenet = "gluenets"
)

type BaseInfo struct {
	Platform    string `json:"platform"`
	HostName    string `json:"host_name"`
	AreaID      string `json:"area_id"`
	Role        string `json:"role"`
	ClusterName string `json:"cluster_name"`
	ParentGUID  string `json:"parent_guid"`
	Organize    string `json:"organize"`
}

func genAgentRegisterInfo(cfg *corev1.Agent) (req *vo2.AgentRegisterReq, err error) {
	var detail *po.AgentDetail

	baseInfo := BaseInfo{
		Platform:    cfg.Platform,
		HostName:    hostdriver.GetHost().HostName,
		AreaID:      cfg.Area,
		Role:        cfg.Role,
		ClusterName: cfg.ClusterName,
		ParentGUID:  cfg.ParentGUID,
		Organize:    cfg.Organize,
	}

	switch platform, _ := cfg.Platform, cfg.Role; {
	case platform == platformGluenet:
		detail, err = baseInfo.gentDockerPlatformInfo()
	case platform == platformK8s:
		detail, err = baseInfo.gentK8sPlatformInfo(depend.Produce[k8sdriver.K8sDriver]())
	default:
		panic("todo")
	}

	if err != nil {
		return
	}

	detail.ClusterName = cfg.ClusterName
	// Search for cluster node
	// cli, _ := v2.NewCoreClient(&rpc.Config{Target: cfg.Guid, NatsUrl: depend.Produce[*rpcdriver.RpcConfig]().NatsUrl})
	// rlt, _ := cli.Maas().VMHostsSearch(&corev2.MaasReq{MaasURL: service.DEFAULT_MAAS_URL, APIKey: service.DEFAULT_MAAS_API_KEY, Version: service.DEFAULT_MAAS_API_VERSION})
	// var vmhosts []maasentity.VMHost
	// _ = json.Unmarshal(rlt, &vmhosts)
	// clusterNodes := make([]po.AgentNodesInfo, len(vmhosts))
	// for i, v := range vmhosts {
	// 	clusterNodes[i].NodeName = v.Name
	// }
	clusterNodes := make([]po.AgentNodeInfo, 0)
	req = &vo2.AgentRegisterReq{
		Platform:     baseInfo.Platform,
		AreaID:       baseInfo.AreaID,
		Role:         baseInfo.Role,
		ClusterName:  baseInfo.ClusterName,
		ClusterNodes: clusterNodes,
		ParentGUID:   baseInfo.ParentGUID,
		Organize:     baseInfo.Organize,
	}
	return
}

func (b BaseInfo) gentK8sPlatformInfo(kd k8sdriver.K8sDriver) (*po.AgentDetail, error) {
	//areaID, err := strconv.Atoi(b.AreaID)
	//if err != nil {
	//	return nil, err
	//}
	return &po.AgentDetail{
		ClusterName: b.ClusterName,
		Area: po.Area{
			AreaID: b.AreaID,
		},
		ParentGuid: b.ParentGUID,
	}, nil
}

func (b BaseInfo) gentDockerPlatformInfo() (*po.AgentDetail, error) {
	//areaID, err := strconv.Atoi(b.AreaID)
	//if err != nil {
	//	return nil, err
	//}
	return &po.AgentDetail{
		ClusterName: b.ClusterName,
		Area: po.Area{
			AreaID: b.AreaID,
		},
		ParentGuid: b.ParentGUID,
	}, nil
}
